package com.fzu.geometa.auth.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fzu.geometa.common.exception.GeometaException;
import com.fzu.geometa.common.model.UserToken;
import com.fzu.geometa.auth.model.po.User;
import com.fzu.geometa.auth.service.AuthService;
import com.fzu.geometa.auth.service.UserService;
import com.fzu.geometa.auth.util.CommunityUtil;
import com.fzu.geometa.auth.util.JwtTokenUtil;
import com.fzu.geometa.auth.util.MailClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static com.fzu.geometa.auth.comm.UserConst.*;

/**
 * @www.codesheep.cn
 * 20190312
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UserService userService;

    @Autowired
    private MailClient mailClient;
    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${community.path.domain}")
    private String domain;
    @Value("${server.servlet.context-path}")
    private String contextPath;

    // 登录
    @Override
    public String login(String username, String password) {

        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username,password);

        try {
            Authentication authentication = authenticationManager.authenticate(upToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }catch (BadCredentialsException e) {
            User user = userService.findUserByName(username);
            if (ObjectUtil.isNull(user)) {
                throw new GeometaException("用户不存在");
            } else {
                throw new GeometaException("密码错误");
            }
        }


        User user = userService.findUserByName(username);
        UserToken userToken = new UserToken();
        userToken.setId(user.getId());
        userToken.setUsername(username);
        userToken.setRole(getRoleString(user.getRole()));

        return jwtTokenUtil.generateToken(userToken);
    }

    // 注册
    @Override
    public User register(User userToAdd ) {
        // 控制判断
        // 参数不能为空
        if (userToAdd == null) {
            throw new IllegalArgumentException("参数不能为空!");
        }
        // 验证账号
        if (StringUtils.isBlank(userToAdd.getUsername())) {
            throw new IllegalArgumentException("账号不能为空!");
        }
        // 验证密码
        if (StringUtils.isBlank(userToAdd.getPassword())) {
            throw new IllegalArgumentException("密码不能为空");
        }
        // 验证邮箱
        if (StringUtils.isBlank(userToAdd.getEmail())) {
            throw new IllegalArgumentException("邮箱不能为空");
        }
        // 验证账号是否重复
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getUsername, userToAdd.getUsername());
        User u = userService.getOne(lqw);

        // 验证用户是否已存在
        if (u != null) {
            throw new IllegalArgumentException("用户已存在");
        }
        //验证邮箱是否被注册
        lqw.clear();
        lqw.eq(User::getEmail, userToAdd.getEmail());
        u = userService.getOne(lqw);

        // 邮箱已存在
        if (u != null) {
            throw new IllegalArgumentException("邮箱已存在");
        }

        //注册用户
        //添加随机字符串
        //userToAdd.setSalt(CommunityUtil.generateUUID().substring(0, 5));
        //密码加密
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        final String rawPassword = userToAdd.getPassword();
        userToAdd.setPassword( encoder.encode(rawPassword) );
        // 普通用户
        userToAdd.setRole(ROLE_USER);
        //未激活
        userToAdd.setStatus(STATUS_NOT_ACTIVATED);
        //激活码
        userToAdd.setActivationCode(CommunityUtil.generateUUID());
        userToAdd.setHeaderUrl(String.format("https://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000)));
        userToAdd.setCreateTime(new Date());
        //保存
        userService.save(userToAdd);
        //发送激活邮件
        Context context = new Context();
        context.setVariable("email", userToAdd.getEmail());
        String url = domain + contextPath + "/activation/" + userToAdd.getId() + "/" + userToAdd.getActivationCode();
        context.setVariable("url", url);
        String content = templateEngine.process("/mail/activation", context);
        mailClient.sendMail(userToAdd.getEmail(), "激活账号", content);
        return userToAdd;
    }

    private String getRoleString(int role) {
        switch (role) {
            case ROLE_ADMIN :
                return "ROLE_ADMIN";
            default:
                return "ROLE_USER";
        }
    }

}
